dojo.provide("slipstream.data.JSONRPCWriteStore");
dojo.require("dojo.rpc.JsonService");
dojo.require("dojo.data.ItemFileWriteStore");
dojo.declare("slipstream.data.JSONRPCWriteStore", dojo.data.ItemFileWriteStore, {
	constructor: function(/* Object */ keywordParameters){
		// create dojo.rpc.JsonService
		// JsonService is called to get SMD
		//if(!(this.service=keywordParameters.service)) this.service = new dojo.rpc.JsonService(keywordParameters.url);
		this.service=(dojo.isObject(keywordParameters.service)?keywordParameters.service:new dojo.rpc.JsonService(keywordParameters.url));
		//console.debug(this.service);
		// set service method that will be invoked
		//this.serviceArgs = keywordParameters.serviceArgs;
		
		this.getMethod = keywordParameters.getMethod;
		this.setMethod = keywordParameters.setMethod;
		this.delMethod = keywordParameters.delMethod;
		this.newMethod = keywordParameters.newMethod;
		this.getArgs = (keywordParameters.getArgs==undefined) ? {} : keywordParameters.getArgs;
		this.setArgs = (keywordParameters.setArgs==undefined) ? {} : keywordParameters.setArgs;
		this.delArgs = keywordParameters.delArgs;
		this.newArgs = keywordParameters.newArgs;
		this.setPrimary = keywordParameters.setPrimary;

		
		// set service method argument names
    	this.serviceArgNames = {}
		
		// introspect service method to get argument names
		var smdMethodArray = this.service.smd.methods
		for (var i in smdMethodArray) {
			var smdMethod = smdMethodArray[i]
			this.serviceArgNames[smdMethod.name]=[];
			var paramArray = smdMethod.parameters
			for (var j in paramArray) {
				this.serviceArgNames[smdMethod.name][j] = paramArray[j].name;
			}
		}
	},

	_fetchItems: function(	/* Object */ keywordArgs, 
							/* Function */ findCallback, 
							/* Function */ errorCallback){
		//	summary: 
		//		See dojo.data.util.simpleFetch.fetch()
		var self = this;
		var filter = function(requestArgs, arrayOfItems){
			var items = [];
			if(requestArgs.query){
				var ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false; 

				//See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
				//same value for each item examined.  Much more efficient.
				var regexpList = {};
				for(var key in requestArgs.query){
					var value = requestArgs.query[key];
					if(typeof value === "string"){
						regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
					}
				}

				for(var i = 0; i < arrayOfItems.length; ++i){
					var match = true;
					var candidateItem = arrayOfItems[i];
					if(candidateItem === null){
						match = false;
					}else{
						for(var key in requestArgs.query) {
							var value = requestArgs.query[key];
							if (!self._containsValue(candidateItem, key, value, regexpList[key])){
								match = false;
							}
						}
					}
					if(match){
						items.push(candidateItem);
					}
				}
				findCallback(items, requestArgs);
			}else{
				// We want a copy to pass back in case the parent wishes to sort the array. 
				// We shouldn't allow resort of the internal list, so that multiple callers 
				// can get lists and sort without affecting each other.  We also need to
				// filter out any null values that have been left as a result of deleteItem()
				// calls in ItemFileWriteStore.
				for(var i = 0; i < arrayOfItems.length; ++i){
					var item = arrayOfItems[i];
					if(item !== null){
						items.push(item);
					}
				}
				findCallback(items, requestArgs);
			}
		};

		if(this._loadFinished){
			filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
		}else{

			if(this._jsonFileUrl){
				//If fetches come in before the loading has finished, but while
				//a load is in progress, we have to defer the fetching to be 
				//invoked in the callback.
				if(this._loadInProgress){
					this._queuedFetches.push({args: keywordArgs, filter: filter});
				}else{
					this._loadInProgress = true;
					/*var getArgs = {
							url: self._jsonFileUrl, 
							handleAs: "json-comment-optional",
							preventCache: this.urlPreventCache
						};
					var getHandler = dojo.xhrGet(getArgs);*/
					var getHandler = this.invokeJSONService(this.getMethod, this.getArgs);
					//getHandler.addCallback(function(data){console.debug(data)});
					getHandler.addCallback(function(data){
						try{
							self._getItemsFromLoadedData(data);
							self._loadFinished = true;
							self._loadInProgress = false;
							
							filter(keywordArgs, self._getItemsArray(keywordArgs.queryOptions));
							self._handleQueuedFetches();
						}catch(e){
							self._loadFinished = true;
							self._loadInProgress = false;
							errorCallback(e, keywordArgs);
						}
					});
					getHandler.addErrback(function(error){
						self._loadInProgress = false;
						errorCallback(error, keywordArgs);
					});
				}
			}else if(this._jsonData){
				try{
					this._loadFinished = true;
					this._getItemsFromLoadedData(this._jsonData);
					this._jsonData = null;
					filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
				}catch(e){
					errorCallback(e, keywordArgs);
				}
			}else{
				errorCallback(new Error("dojo.data.ItemFileReadStore: No JSON source data was provided as either URL or a nested Javascript object."), keywordArgs);
			}
		}
	},
	onSet: function(item, attr, oldVal, newVal) {
		if(oldVal!=newVal){
			//console.debug("Setting "+attr+" of "+item+" from "+oldVal+" to "+newVal);
			var _args=this.setArgs;
			_args.data={};
			_args.data[attr]=newVal;
			_args.id=(Number(item[this.setPrimary][0]));
			//console.debug(_args);
			this.invokeJSONService(this.setMethod, _args);
		}
	},
    invokeJSONService: function(method, args){
        // hold getMethod arguments in array
		//console.debug(request);
    	var serviceArgValues = [];
    	
    	// get getMethod arguments from serverQuery by name defined in SMD
    	for (var i in this.serviceArgNames[method]) {
    		serviceArgValues[i] = args[this.serviceArgNames[method][i]];
    	}
		//console.debug(serviceArgValues);
		
		// call service method    	
		return this.service[method].apply(this, serviceArgValues);
    }
});